/*
 * Copyright (c) 2007-2008, Thomas Krause (tho.krause@gmail.com)
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *     * Neither the name of gidoo nor the names of its contributors may be used to
 *       endorse or promote products derived from this software without specific
 *       prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.gidoo.cms.view;

import java.util.logging.Level;
import java.util.logging.Logger;
import org.gidoo.cms.GidooCMS;
import java.io.PrintWriter;
import java.io.StringWriter;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import org.apache.wicket.RequestCycle;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.pages.RedirectPage;
import org.apache.wicket.model.Model;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.request.target.resource.ResourceStreamRequestTarget;
import org.gidoo.cms.helper.Tools;
import org.gidoo.cms.helper.CMSResourceStreamWriter;
import org.gidoo.cms.jcr.JcrHelper;
import org.gidoo.cms.login.GidooCMSSession;

/**
 * Catches the data from the database, transforms using XSLT it and renders it 
 * for the visitor.<br>
 * <br>
 * If you want to customize the appearance of you webpage ("template") or if you 
 * want to add navigation, user-specific stuff etc. you should override this 
 * default class an should use the overridden class in the 
 * {@link org.gidoo.cms.GidooCMS#init} 
 * function.
 * @author <a href="mailto:tho.krause@gmail.com">Thomas Krause</a>
 */
public class ContentView extends WebPage
{
  /** Label containg the content of the page. */
  protected Label content;
  
  /** Label containg the title of the page. */
  protected Label title;
  
  /** 
   * The folder which matches the request path. 
   * Usally set by {@link #generateSite(String)} 
   */
  protected Node currentFolder;
  
  /** Creates a new instance of ContentView */
  public ContentView()
  {
    String path = this.getRequest().getPath();
    
    if(path == null)
    {
      path = "";
    }
    
    String cmsPath = ((GidooCMS) getApplication()).getCMSPath();
    if(path.startsWith(cmsPath))
    {
      path = path.replaceFirst(cmsPath, "");
    }
    
    // some cleanup
    path = Tools.cleanupFolderPath(path);
    
    createAndAddComponents();
    
    try
    {
      generateSite(path);
      if(currentFolder != null)
      {
        ((GidooCMSSession) getSession()).setLastVisitedFolder(currentFolder);
      }
    }
    catch(PathNotFoundException ex)
    {
      generateFileNotFoundPage();
    }
    catch(ContentGenerationFailedException ex)
    {
      generateInternalErrorPage(ex);
    }
  }
  
  /**
   * Use this function to create all needed components and add them to the page.
   * The default implementation will create and add
   * {@link #content} and {@link #title}.
   */
  protected void createAndAddComponents()
  {
    content = new Label("content", new Model(""));
    title = new Label("title", new Model(""));
    add(content);
    add(title);
  }
  
  /**
   * Creates all content of the site. Override this to manipulate content generation.
   * @param path The path of the user request.
   */
  protected  void generateSite(String path) throws ContentGenerationFailedException, PathNotFoundException
  {      
    try
    {
      currentFolder = JcrHelper.getPublishedPageByPath(
        path, ((GidooCMSSession) getSession()));
      
      if(currentFolder != null)
      {
        if(!getRequest().getPath().endsWith("/"))
        {
          // force reload since pages without / can cause problemes with relative links
          WebApplication app = (WebApplication) getApplication();
          this.setResponsePage(new RedirectPage(
            app.getServletContext().getContextPath() + "/" + getRequest().getPath() + "/"));
          return;
        }
              
        generateContent(currentFolder);
        generateTitle(currentFolder);
      }
      else
      {
        // try to find a resource
        Node res = 
          JcrHelper.getResourceByPath(path, (GidooCMSSession) getSession());
        if(res != null)
        {
          generateResourceDownload(res);
        }
        else
        {
          throw new PathNotFoundException();
        }
      }
    }
    catch (RepositoryException ex)
    {
      Logger.getLogger(ContentView.class.getName()).log(Level.SEVERE, null, ex);
      throw new ContentGenerationFailedException(ex.getMessage());
    }
  }
  
  /** Fills a label with the id "content" with the parsed content of the XML-file */
  protected  void generateContent(Node page) throws ContentGenerationFailedException
  {
    try
    {
      String html = 
        ((GidooCMS) getApplication()).transformContent(page.getProperty("cms:xml").getString());
      
      content.setModelObject(html);
      content.setEscapeModelStrings(false);
    }
    catch(RepositoryException ex)
    {
      throw new ContentGenerationFailedException(ex.getMessage());
    }
    catch(XSLTTransformFailedException ex)
    {
      throw new ContentGenerationFailedException(ex.getMessage());
    }
  }
  
  /** Fills a label with the id "title" with the parsed title of the XML-file */
  protected  void generateTitle(Node page)
  throws ContentGenerationFailedException
  {
    try
    {
      title.setModelObject(page.getProperty("cms:title").getString());
      title.setEscapeModelStrings(false);
    }
    catch(RepositoryException ex)
    {
      throw new ContentGenerationFailedException(ex.getMessage());
    }
  }
  
  /** Will generate a resource as the response to the request. */
  protected void generateResourceDownload(Node res)
  {
    CMSResourceStreamWriter writer = 
      new CMSResourceStreamWriter(res, (GidooCMS) getApplication());
    
    RequestCycle.get().setRequestTarget(
      new ResourceStreamRequestTarget(writer));
  }
  
  /** Generates a page informing the user, that the file was not found. */
  protected void generateFileNotFoundPage()
  {
    try
    {      
      title.setModelObject(getString("error404short"));
      content.setModelObject("<h1>" + getString("error404long") +"</h1>" +
        "<p>" + getString("filewasnotfound") + "</p>");
      content.setEscapeModelStrings(false);
      
      getWebRequestCycle().getWebResponse().getHttpServletResponse().setStatus(404);
    }
    catch(Exception ex)
    {
      generateInternalErrorPage(ex);
    }
  }
  
  /** Generates a page informing the user about an internal error*/
  protected  void generateInternalErrorPage(Exception ex)
  {
    // for the logs
    Logger.getLogger(ContentView.class.getName()).log(Level.SEVERE, null, ex);
    
    // for the user    
    title.setModelObject(getString("error500short"));
    
    StringWriter stackWriter = new StringWriter();
    ex.printStackTrace(new PrintWriter(stackWriter));
    
    content.setModelObject("<h1>" + getString("error500long") + "</h1>" +
      "<p>" + getString("internalservererror") + "</p>" +
      "<p>" + getString("reason") +"<br/>" + ex.getMessage() +
      "<p>" + getString("stacktrace") + "<br/>" + stackWriter.toString().replaceAll("\n", "<br/>"));
    content.setEscapeModelStrings(false);

    getWebRequestCycle().getWebResponse().getHttpServletResponse().setStatus(500);
  }
  
}
